﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;

public static class CsvHelper
{
    // 配置表的相对目录
    private readonly static string CFG_Dir = "Configs";

    // read int key csv
    public static Dictionary<int, T> ReadIntCsv<T>(string name, char split = ',') where T : class, new()
    {
        string path = GetCfgPath(name);
        Dictionary<int, T> cfg = null;
        try
        {
            var ld = Resources.Load<TextAsset>(path);
            var bs = ld.bytes;
            Dictionary<string, T> dic = ReadStringCsv<T>(bs, null, split);
            cfg = new Dictionary<int, T>();

            // key 由 string 转 int
            foreach (KeyValuePair<string, T> para in dic)
                cfg.Add(int.Parse(para.Key), para.Value);  
        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("解析csv配置表{0}出错，{1}{2}", name, ex.Message, ex.StackTrace));
        }

        return cfg;
    }

    // read string key csv
    public static Dictionary<string, T> ReadStringCsv<T>(string name, Func<T, string> keyGenFunc = null, char split = ',') where T : class, new()
    {
        string path = GetCfgPath(name);
        Dictionary<string, T> cfg = null;
        try
        {
            var ld = Resources.Load<TextAsset>(path);
            var bs = ld.bytes;
            cfg = ReadStringCsv<T>(bs, keyGenFunc, split);
        }
        catch (Exception ex)
        {
            throw new Exception(string.Format("解析csv配置表{0}出错，{1}{2}", name, ex.Message, ex.StackTrace));
        }

        return cfg;
    }

    public static T GetCfg<T>(int key, Dictionary<int, T> infos)
    {
        T t = default(T);
        infos.TryGetValue(key, out t);
        return t;
    }

    public static T GetCfg<T>(string key, Dictionary<string, T> infos)
    {
        T t = default(T);
        if (!string.IsNullOrEmpty(key))
            infos.TryGetValue(key, out t);
        return t;
    }

    // 组织配置表的相对路径
    private static string GetCfgPath(string fileName)
    {
        return string.Format("{0}/{1}", CFG_Dir, fileName);
    }

    public static Dictionary<string, T> ReadStringCsv<T>(byte[] bytes, Func<T, string> keyGenFunc = null, char split = ',') where T : class, new()
    {
        string txt = System.Text.UTF8Encoding.UTF8.GetString(bytes);
        if (string.IsNullOrEmpty(txt))
            return null;

        Dictionary<string, T> dic = new Dictionary<string, T>();

        string[] lines = txt.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
        string[] sec = null;
        bool first = true;

        Type cT = typeof(T);

        MethodInfo _init = cT.GetMethod("Init");

        try
        {
            for (int i = 0; i < lines.Length; i++)
            {
                string line = lines[i];
                if (string.IsNullOrEmpty(line))
                    continue;

                if (line[0] == '#')
                    // 注释
                    continue;

                string[] para = line.Split(split);

                if (first)
                {
                    // 字段
                    sec = para;
                    first = false;
                    continue;
                }
                else
                {
                    // 内容
                    T t = new T();

                    // 后继：需要可以支持Dbase

                    for (int j = 0; j < para.Length; j++)
                    {
                        PropertyInfo info = cT.GetProperty(sec[j].Trim());
                        if (null == info)
                            continue;

                        Type vT = info.PropertyType;
                        string val = para[j];

                        if (vT == typeof(System.String))
                        {
                            info.SetValue(t, val, null);
                        }
                        else if (vT == typeof(System.Int32))
                        {
                            int myValue = 0;
                            int.TryParse(val, out myValue);
                            info.SetValue(t, myValue, null);
                        }
                        else if (vT == typeof(System.Double))
                        {
                            info.SetValue(t, double.Parse(val), null);
                        }
                        else if (vT == typeof(float))
                        {
                            info.SetValue(t, float.Parse(val), null);
                        }
                        else if (vT == typeof(Boolean))
                        {
                            info.SetValue(t, Boolean.Parse(val), null);
                        }
                        else if (vT.IsEnum)
                        {
                            info.SetValue(t, Enum.Parse(vT, val), null);
                        }
                    }

                    // 调用初始化方法
                    if (null != _init)
                    {
                        object r = _init.Invoke(t, null);
                        if (null != r)
                        {
                            if (r is bool && !(bool)r)
                                continue;
                        }
                    }

                    string key = para[0];
                    if (null != keyGenFunc)
                        key = keyGenFunc(t);

#if UNITY_EDITOR
                    if (dic.ContainsKey(key))
                        UnityEngine.Debug.Log("Csv key: " + key);
#endif

                    dic.Add(key, t);
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception("解析csv文件出错: " + ex.Message);
        }

        return dic;
    }
}
